package com.dusk.tool
{
	import flash.display.Stage;
	import flash.events.KeyboardEvent;
	import flash.text.TextField;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	
	public class KeyBoarder
	{
		private static var _instance:KeyBoarder;
		
		private var _keyId:uint = 0;
		
		private var _lastKeyId:uint = 0;
		
		private var _listenStage:Stage;
		
		private var _lastKeyCode:uint = 0;
		
		private var _doublePressDelay:int = 500;
		
		private var _keyHistory:Vector.<KeyVO> = new Vector.<KeyVO>();
		
		private var _keyDownDict:Dictionary = new Dictionary();
		
		private var _functionVector:Vector.<Function> = new Vector.<Function>();
		
		private var _keyLastDownTime:Dictionary = new Dictionary();
		
		public function KeyBoarder(stage:Stage = null)
		{
			if(_instance)
			{
				_instance.destroy();
			}
			_instance = this;
			if(stage)
			{
				setStage(stage)
			}
		}
		
		public static function getIns():KeyBoarder
		{
			if(!_instance)
			{
				_instance = new KeyBoarder();
			}
			return _instance;
		}
		
		public function setStage(stage:Stage):void
		{
			_listenStage = stage;
			_listenStage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			_listenStage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
		}
		
		public function registerFunction(func:Function):void
		{
			_functionVector.push(func);
		}
		
		public function removeFunction(func:Function):void
		{
			if(_functionVector.indexOf(func) != -1)
			{
				_functionVector.splice(_functionVector.indexOf(func),1);
			}
		}
		
		public function setDoublePressDelay(delay:int):void
		{
			_doublePressDelay = delay;
		}
		
		public function isUp(keyCode:int):Boolean
		{
			return !Boolean(_keyDownDict[keyCode]);
		}
		
		public function isDown(keyCode:int):Boolean
		{
			return _keyDownDict[keyCode] && _keyDownDict[keyCode] >= 1;
		}
		
		public function isDoublePress(keyCode:int):Boolean
		{
			return _keyDownDict[keyCode] == 2;
		}
		
		public function cancelDoublePress(keyCode:int):void
		{
			_keyDownDict[keyCode] = 0;
		}
		
		public function getLastKey():KeyVO
		{
			return _keyHistory[_keyHistory.length - 1];
		}
		
		public function getLastKeyCode():uint
		{
			return getLastKey().keyCode;
		}
		
		public function getLastKeyCharCode():uint
		{
			return getLastKey().charCode;
		}
		
		public function getLastKeyCharString():String
		{
			return getLastKey().charString;
		}
		
		public function getLastKeyDuration():uint
		{
			return getLastKey().duration;
		}
		
		private function onKeyDown(evt:KeyboardEvent):void
		{
			if(_listenStage.focus is TextField)
			{
				return;
			}
			if(isUp(evt.keyCode))
			{
				_keyDownDict[evt.keyCode] = 1;
			}
			if(evt.keyCode != _lastKeyCode)
			{
				_keyId ++;
			}
			if(_keyId != _lastKeyId)
			{
				if(_lastKeyCode == evt.keyCode && getTimer() - _keyLastDownTime[evt.keyCode] < _doublePressDelay)
				{
					_keyDownDict[evt.keyCode] = 2;
				}
			}
			var i:int = _functionVector.length;
			while(i)
			{
				_functionVector[--i].call(null,evt);
			}
			_lastKeyCode = evt.keyCode;
			_lastKeyId = _keyId;
			_keyLastDownTime[evt.keyCode] = getTimer();
		}
		
		private function onKeyUp(evt:KeyboardEvent):void
		{
			if(_listenStage.focus is TextField)
			{
				return;
			}
			_keyDownDict[evt.keyCode] = 0;
			if(evt.keyCode == _lastKeyCode)
			{
				_keyId ++;
				var vo:KeyVO = new KeyVO();
				vo.setDataFromEvent(evt);
				vo.downTime = _keyLastDownTime[evt.keyCode];
				vo.upTime = getTimer();
				_keyHistory.push(vo);
			}
			var i:int = _functionVector.length;
			while(i)
			{
				_functionVector[--i].call(null,evt);
			}
		}
		
		public function destroy():void
		{
			_listenStage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			_listenStage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
			_functionVector.length = 0;
			_functionVector = null;
			_keyDownDict = null;
			_keyHistory = null;
			_keyLastDownTime = null;
			_listenStage = null;
			_instance = null;
		}
	}
}

import flash.events.KeyboardEvent;

class KeyVO
{
	public var keyCode:uint;
	public var charCode:uint;
	public var charString:String;
	public var downTime:uint;
	public var upTime:uint;
	
	public function setDataFromEvent(evt:KeyboardEvent):void
	{
		keyCode = evt.keyCode;
		charCode = evt.charCode;
		charString = String.fromCharCode(charCode);
	}
	
	public function get duration():uint
	{
		return upTime - downTime;
	}
}